home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3.2 / Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO / packet / n17jsrc / wildmat.c < prev   
C/C++ Source or Header  |  1990-12-11  |  4KB  |  160 lines

  1.  
  2. /*
  3.  * @(#)wildmat.c 1.3 87/11/06    Public Domain.
  4.  *
  5. From: rs@mirror.TMC.COM (Rich Salz)
  6. Newsgroups: net.sources
  7. Subject: Small shell-style pattern matcher
  8. Message-ID: <596@mirror.TMC.COM>
  9. Date: 27 Nov 86 00:06:40 GMT
  10.  
  11. There have been several regular-expression subroutines and one or two
  12. filename-globbing routines in mod.sources.  They handle lots of
  13. complicated patterns.  This small piece of code handles the *?[]\
  14. wildcard characters the way the standard Unix(tm) shells do, with the
  15. addition that "[^.....]" is an inverse character class -- it matches
  16. any character not in the range ".....".  Read the comments for more
  17. info.
  18.  
  19. For my application, I had first ripped off a copy of the "glob" routine
  20. from within the find(1) source, but that code is bad news:  it recurses
  21. on every character in the pattern.  I'm putting this replacement in the
  22. public domain.  It's small, tight, and iterative.  Compile with -DTEST
  23. to get a test driver.  After you're convinced it works, install in
  24. whatever way is appropriate for you.
  25.  
  26. I would like to hear of bugs, but am not interested in additions; if I
  27. were, I'd use the code I mentioned above.
  28. */
  29. /*
  30. **  Do shell-style pattern matching for ?, \, [], and * characters.
  31. **  Might not be robust in face of malformed patterns; e.g., "foo[a-"
  32. **  could cause a segmentation violation.
  33. **
  34. **  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
  35. */
  36.  
  37. /*
  38.  * Modified 6Nov87 by John Gilmore (hoptoad!gnu) to return a "match"
  39.  * if the pattern is immediately followed by a "/", as well as \0.
  40.  * This matches what "tar" does for matching whole subdirectories.
  41.  *
  42.  * The "*" code could be sped up by only recursing one level instead
  43.  * of two for each trial pattern, perhaps, and not recursing at all
  44.  * if a literal match of the next 2 chars would fail.
  45.  */
  46.  
  47. /* Modified by Anders Klemets to take an array of pointers as an optional
  48.    argument. Each part of the string that matches '*' is returned as a
  49.    null-terminated, malloced string in this array.
  50.  */
  51. #include "global.h"
  52. static int Star __ARGS((char *s,char *p,char **argv));
  53.  
  54. static int
  55. Star(s,p,argv)
  56. register char *s;
  57. register char *p;
  58. register char **argv;
  59. {
  60.     char *cp = s;
  61.     while (wildmat(cp, p, argv) == FALSE)
  62.         if(*++cp == '\0')
  63.             return -1;
  64.     return cp - s;
  65. }
  66.  
  67. int
  68. wildmat(s,p,argv)
  69. register char *s;
  70. register char *p;
  71. register char **argv;
  72. {
  73.     register int last;
  74.     register int matched;
  75.     register int reverse;
  76.     register int cnt;
  77.  
  78.     for(; *p; s++,p++){
  79.         switch(*p){
  80.         case '\\':
  81.             /* Literal match with following character; fall through. */
  82.             p++;
  83.         default:
  84.             if(*s != *p)
  85.                 return FALSE;
  86.             continue;
  87.         case '?':
  88.             /* Match anything. */
  89.             if(*s == '\0')
  90.                 return FALSE;
  91.             continue;
  92.         case '*':
  93.             /* Trailing star matches everything. */
  94.             if(argv == NULLCHARP)
  95.                 return *++p ? 1 + Star(s, p, NULLCHARP) : TRUE;
  96.             if(*++p == '\0'){
  97.                 cnt = strlen(s);
  98.             } else {
  99.                 if((cnt = Star(s, p, argv+1)) == -1)
  100.                     return FALSE;
  101.             }
  102.             *argv = mallocw(cnt+1);
  103.             strncpy(*argv,s,cnt);
  104.             *(*argv + cnt) = '\0';
  105.             return TRUE;
  106.         case '[':
  107.             /* [^....] means inverse character class. */
  108.             reverse = (p[1] == '^') ? TRUE : FALSE;
  109.             if(reverse)
  110.                 p++;
  111.             for(last = 0400, matched = FALSE; *++p && *p != ']'; last = *p){
  112.                 /* This next line requires a good C compiler. */
  113.                 if(*p == '-' ? *s <= *++p && *s >= last : *s == *p)
  114.                     matched = TRUE;
  115.             }
  116.             if(matched == reverse)
  117.                 return FALSE;
  118.             continue;
  119.         }
  120.     }
  121.     /* For "tar" use, matches that end at a slash also work. --hoptoad!gnu */
  122.     return *s == '\0' || *s == '/';
  123. }
  124.  
  125.  
  126. #ifdef    TEST
  127. #include <stdio.h>
  128.  
  129. extern char *gets();
  130.  
  131. main()
  132. {
  133.     char pattern[80];
  134.     char text[80];
  135.     char *argv[80], *cp;
  136.     int cnt;
  137.     
  138.     while (TRUE){
  139.         printf("Enter pattern:  ");
  140.         if(gets(pattern) == NULL)
  141.             break;
  142.         while (TRUE){
  143.             bzero(argv,80*sizeof(char *));
  144.             printf("Enter text:  ");
  145.             if(gets(text) == NULL)
  146.                 exit(0);
  147.             if(text[0] == '\0')
  148.                 /* Blank line; go back and get a new pattern. */
  149.                 break;
  150.             printf("      %d\n", wildmat(text, pattern, argv));
  151.             for(cnt = 0; argv[cnt] != NULLCHAR; ++cnt){
  152.                 printf("String %d is: '%s'\n",cnt,argv[cnt]);
  153.                 free(argv[cnt]);
  154.             }
  155.         }
  156.     }
  157.     exit(0);
  158. }
  159. #endif    /* TEST */
  160.